%{

#include <cstring>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <vector>

#include "commun.h"
#include "xml/XMLDocument.h"
#include "xml/XMLEntity.h"
#include "xml/XMLElement.h"
#include "xml/XMLSpecial.h"
#include "xml/XMLNode.h"
#include "xml/XMLText.h"
#include "xml.tab.h"

using namespace std;

int xmlwrap(void);
void xmlerror(char *msg);
int xmllex(void);

char dtd [ 255 ];
XMLDocument * doc = NULL;

%}

%error-verbose

%union {
	char * s;
	ElementName * en; /* Nom d'un élément + namespace */
	XMLDocument * doc;
	XMLNode * node;
	AttList * attrs;
	std::vector<XMLNode *> * temp;
}

%token EQ SLASH CLOSE END CLOSESPECIAL DOCTYPE
%token <s> ENCODING VALUE DATA COMMENT NAME NSNAME
%token <en> NSSTART START STARTSPECIAL
%type <en> start
%type <doc> document
%type <node> declaration element
%type <attrs> attributes
%type <temp> content declarations close_content_and_end empty_or_content

%%

document
 : declarations element misc_seq_opt
 {
 	$$ = new XMLDocument();
 	$$->setChildList(*$1);
 	$$->addElement((XMLElement *) $2);
 	$$->setRootNode((XMLElement *) $2);
 	doc = $$;
 }
 ;
 
misc_seq_opt
 : misc_seq_opt misc
 | /*empty*/
 ;
 
misc
 : COMMENT
 ;

declarations
 : declarations declaration
 {
 	$$ = $1;
 	$$->push_back((XMLNode *) $2);
 }
 | /* empty */
 {
 	$$ = new vector<XMLNode *>();
 }
 ;
 
declaration
 : DOCTYPE NAME NAME VALUE CLOSE
 {
	 strcpy ( dtd, $4 );
	 $$ = new XMLEntity("DOCTYPE");
	 ((XMLEntity *) $$)->addAttribute($2);
	 ((XMLEntity *) $$)->addAttribute($3);
	 ((XMLEntity *) $$)->addAttribute($4);
 }
 | STARTSPECIAL attributes CLOSESPECIAL
 {
 	$$ = new XMLSpecial($1->second);
 }
 ;

element
 : start
   attributes
   empty_or_content
{
	$$ = new XMLElement($1->second);
	((XMLElement *) $$)->setAttributes(*$2);
	if ($3 != NULL) /* Empty */
	{
		for (int i = 0; i < $3->size();i++)
		{ 
			((XMLElement *) $$)->addChild($3->at(i));
		}
	}
}
 ;
 
start
 : START
 {
 	$$ = $1;
 }
 | NSSTART
 {
 	$$ = $1;
 }
 ;
 
empty_or_content
 : SLASH CLOSE { $$ = NULL; }
 | close_content_and_end name_or_nsname_opt CLOSE
 {
 	$$ = $1;
 }
 ;
 
name_or_nsname_opt
 : NAME
 | NSNAME
 | /* empty */
 ;
 
close_content_and_end
 : CLOSE content END
 {
 	$$ = $2;
 }
 ;
 
content 
 : content DATA
 {
 	$$ = $1;
 	$$->push_back(new XMLText($2));
 }
 | content misc
 | content element
 {
 	$$ = $1;
 	$$->push_back($2);
 }
 | /* empty */
 {
 	$$ = new vector<XMLNode *>();
 }
 ;

attributes
 : attributes NAME EQ VALUE
 {
 	$$ = $1;
 	$$->push_back(make_pair($2, $4));
 }
 | /* empty */
 {
 	$$ = new AttList();
 }
 ;

%%

/*
int main(int argc, char **argv)
{
  int err;

  err = yyparse();
  if (err != 0) printf("Parse ended with %d error(s)\n", err);
  	else  printf("Parse ended with sucess\n", err);
  return 0;
}
*/

int xmlwrap(void)
{
  return 1;
}

void xmlerror(char *msg)
{
  fprintf(stderr, "%s\n", msg);
}
